using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace ArkanoidX.Objects
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class Shots : BaseComponent
    {
        /*
         * TODO: optimisation needed to improve space utility
         */
        public class Shot : IPhysicalObject
        {
            public Vector2 Position;
            public Vector2 Velocity;

            public Vector2 TargetHalfSize;
            public Vector2 TargetFullSize;
            public Rectangle SourceRect;
            public Texture2D Texture;

            public Shots Manager;
            public bool _perished = false;

            public Rectangle TargetRect
            {
                get
                {
                    return Utility.GetRectangle(this.Position, this.TargetHalfSize);
                }
            }

            public float Weight
            {
                get
                {
                    return 0f;
                }
            }

            public void Perish()
            {
                if (!this._perished)
                {
                    Manager._removeList.Add(this);
                    this._perished = true;
                }
            }
        }


        public TimeSpan _lastGameTime = default(TimeSpan);


        List<Shot> _shots = new List<Shot>();
        List<Shot> _removeList = new List<Shot>();

        Bricks _bricks = null;

        Texture2D _shotTexture;
        Rectangle _shotSourceRect;

        Rectangle _reachableArea;

        public Shots(Game game, Rectangle reachableArea, Bricks bricks)
            : base(game)
        {
            // TODO: Construct any child components here
            _bricks = bricks;
            _reachableArea = reachableArea;

            _shotTexture = Game.Content.Load<Texture2D>("shot");
            _shotSourceRect = _shotTexture.Bounds;
        }



        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here

            if (_lastGameTime != default(TimeSpan))
            {
                int miliseconds = (gameTime.TotalGameTime - _lastGameTime).Milliseconds;

                foreach (Shot shot in _shots)
                {
                    shot.Position += shot.Velocity * miliseconds;

                    CheckShotOutOfBounds(shot);

                    _bricks.Collides(shot);
                }
                Cleanup();  /* remove all shots that have hit the target */
            }
            _lastGameTime = gameTime.TotalGameTime;

            base.Update(gameTime);
        }

        public void CheckShotOutOfBounds(Shot shot)
        {
            bool toPerish = false;
            if (shot.Position.Y + shot.TargetHalfSize.Y < _reachableArea.Top)
            {
                toPerish = true;
            }

            if (toPerish)
            {   // hope it will nicely perish from now on
                shot.Perish();
            }
        }

        public void Cleanup()
        {
            foreach (Shot shot in _removeList)
            {
                _shots.Remove(shot);
            }
            _removeList.Clear();
        }

        public override void Draw(GameTime gameTime)
        {
            SpriteBatch sBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));

            if (_shots.Count == 0) return;

            foreach (Shot shot in _shots)
            {
                Utility.Draw(sBatch, shot.Texture, shot.Position, shot.TargetHalfSize, 
                    shot.SourceRect, Color.White);
            }

            base.Draw(gameTime);
        }

        public void Generate(Vector2 position)
        {
            Generate(position, new Vector2(0, -0.3f));
        }

        public void Generate(Vector2 position, Vector2 velocity)
        {
            Vector2 fullSize = new Vector2(_shotSourceRect.Width, _shotSourceRect.Height);
            fullSize = fullSize * 0.4f;
            Vector2 halfSize = fullSize * 0.5f;

            Shot shot = new Shot()
            {
                Position = position,
                Velocity = velocity,
                TargetFullSize = fullSize,
                TargetHalfSize = halfSize,
                SourceRect = _shotSourceRect,
                Texture = _shotTexture,
                Manager = this
            };
            _shots.Add(shot);
        }
    }
}
